//
//  WCarouselScrollView.m
//  WCycleScrollView
//
//  Created by winter on 16/8/2.
//  Copyright © 2016年 d. All rights reserved.
//

#import "WCarouselScrollView.h"

@interface WCarouselLayout : UICollectionViewLayout
@property (nonatomic) CGSize itemSize;
@property (nonatomic) UICollectionViewScrollDirection scrollDirection;
@end

#pragma mark -
#pragma mark - WCarouselScrollView

@interface WCarouselScrollView ()<UICollectionViewDelegate,UICollectionViewDataSource>
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) WCarouselLayout *layout;


- (void)scrollToItemAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated;
@end

@implementation WCarouselScrollView

- (instancetype)initWithFrame:(CGRect)frame itemSize:(CGSize)itemSize
{
    self = [self initWithFrame:frame];
    if (!self) {
        return nil;
    }
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.itemSize = itemSize;
    return self;
}

- (void)setItemSize:(CGSize)itemSize
{
    _itemSize = itemSize;
    
    if (self.layout) {
        self.layout.itemSize = itemSize;
    }
    else
        [self setupCollectionView];
}

- (void)setScrollDirection:(UICollectionViewScrollDirection)scrollDirection
{
    _scrollDirection = scrollDirection;
    self.layout.scrollDirection = scrollDirection;
}

- (void)setBackgroundView:(UIView *)backgroundView
{
    _backgroundView = backgroundView;
    if (!self.collectionView) {
        [self setupCollectionView];
    }
    self.collectionView.backgroundView = backgroundView;
}

- (void)setupCollectionView
{
    self.layout = [[WCarouselLayout alloc] init];
    self.layout.itemSize = self.itemSize;
    self.layout.scrollDirection = self.scrollDirection;
    
    self.collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:self.layout];
    self.collectionView.dataSource = self;
    self.collectionView.delegate = self;
    self.collectionView.backgroundColor = [UIColor clearColor];
    self.collectionView.showsVerticalScrollIndicator = NO;
    self.collectionView.showsHorizontalScrollIndicator = NO;
    [self addSubview:self.collectionView];
}

- (void)reloadData
{
    [self.collectionView reloadData];
}

- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier
{
    [self.collectionView registerClass:cellClass forCellWithReuseIdentifier:@"cell"];
}

- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier
{
    [self.collectionView registerNib:nib forCellWithReuseIdentifier:@"cell"];
}

- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated
{
    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) {
        [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:animated];
    }
    else
        [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:animated];
}

- (NSIndexPath *)currentIndexPath
{
    NSArray *indexPaths = [self.collectionView indexPathsForVisibleItems];
    NSIndexPath *curIndexPath = nil;
    NSInteger curzIndex = 0;
    for (NSIndexPath *path in indexPaths.objectEnumerator) {
        UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:path];
        if (!curIndexPath) {
            curIndexPath = path;
            curzIndex = attributes.zIndex;
            continue;
        }
        if (attributes.zIndex > curzIndex) {
            curIndexPath = path;
            curzIndex = attributes.zIndex;
        }
    }
    return curIndexPath;
}

- (void)setCollectionViewUserInteractionEnabled:(NSNumber *)anArgument
{
    [self.collectionView setUserInteractionEnabled:[anArgument boolValue]];
}

- (UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(nullable NSString *)identifier forIndex:(NSInteger)index;
{
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
    return [self.collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
}

#pragma mark - UICollectionView Delegate / DataSource

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    BOOL canResponseProtocol  = [self.dataSource respondsToSelector:@selector(numberOfItemsForCarouselScrollView)];
    NSAssert(canResponseProtocol, @"must implementate 'numberOfItemsForCarouselScrollView'");
    return [self.dataSource numberOfItemsForCarouselScrollView];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    BOOL canResponseProtocol  = [self.dataSource respondsToSelector:@selector(carouselScrollView:cellForItemAtIndex:)];
    NSAssert(canResponseProtocol, @"must implementate 'carouselScrollView:cellForItemAtIndex:'");
    return [self.dataSource carouselScrollView:self cellForItemAtIndex:indexPath.item];
}

// 点击滚动至中间显示, 如果点击的是中间的，则响应(collectionView:didSelectItemAtIndexPath:)
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSIndexPath *curIndexPath = [self currentIndexPath];
    if (curIndexPath.item == indexPath.item) {
        return YES;
    }
    
    // 防止连续点击造成 滚动出错
    [collectionView setUserInteractionEnabled:NO];
    [self performSelector:@selector(setCollectionViewUserInteractionEnabled:)
               withObject:[NSNumber numberWithBool:YES] afterDelay:0.5f];
    
    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) {
        [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
    }
    else
        [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
    return NO;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self.delegate respondsToSelector:@selector(carouselScrollView:didSelectItemAtIndex:)]) {
        [self.delegate carouselScrollView:self didSelectItemAtIndex:indexPath.item];
    }
}

@end

#pragma mark -
#pragma mark - WCarouselLayout

static NSInteger visibleCount = 3;

@interface WCarouselLayout ()
/** collectionView 的宽或者高 */
@property (nonatomic, assign) CGFloat viewWH;
/** cell 的宽或者高 */
@property (nonatomic, assign) CGFloat itemWH;

@end

@implementation WCarouselLayout

// 准备布局
- (void)prepareLayout
{
    [super prepareLayout];
    
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        // 垂直滚动
        self.viewWH = CGRectGetHeight(self.collectionView.frame);
        self.itemWH = self.itemSize.height;
        CGFloat edgeInsetValue = (self.viewWH - self.itemWH) / 2.0;
        self.collectionView.contentInset = UIEdgeInsetsMake(edgeInsetValue, 0, edgeInsetValue, 0);
    }
    else {
        // 水平滚动
        self.viewWH = CGRectGetWidth(self.collectionView.frame);
        self.itemWH = self.itemSize.width;
        CGFloat edgeInsetValue = (self.viewWH - self.itemWH) / 2.0;
        // 将第一个和最后一个item显示在中间
        self.collectionView.contentInset = UIEdgeInsetsMake(0, edgeInsetValue, 0, edgeInsetValue);
    }
}

// 根据 itemSize 计算 ContentSize
- (CGSize)collectionViewContentSize
{
    NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        return CGSizeMake(CGRectGetWidth(self.collectionView.frame), cellCount * self.itemWH);
    }
    return CGSizeMake(cellCount * self.itemWH, CGRectGetHeight(self.collectionView.frame));
}

// 计算每个显示在屏幕上的cell位置大小布局
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    layoutAttributes.size = self.itemSize;
    
    CGFloat itemCenterSpace = self.itemWH * ((float)indexPath.item + 1/2.0);
    CGFloat viewCenterSpace = 0.0;
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        viewCenterSpace = self.collectionView.contentOffset.y + self.viewWH/2.0;
    }
    else viewCenterSpace = self.collectionView.contentOffset.x + self.viewWH/2.0;
    layoutAttributes.zIndex = -ABS(itemCenterSpace - viewCenterSpace);
    
    CGFloat delta = viewCenterSpace - itemCenterSpace;
    CGFloat ratio = -delta / (self.itemWH*2.0);
    CGFloat scale = 1 - ABS(delta) / (self.itemWH * 6.0) * cos(ratio * M_PI_4);
    layoutAttributes.transform = CGAffineTransformMakeScale(scale, scale);
    
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        layoutAttributes.center = CGPointMake(CGRectGetWidth(self.collectionView.frame) / 2.0, itemCenterSpace);
    }
    else layoutAttributes.center = CGPointMake(itemCenterSpace, CGRectGetHeight(self.collectionView.frame) / 2.0);
    
    return layoutAttributes;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    CGFloat viewCenterSpace = 0.0;
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        viewCenterSpace = self.collectionView.contentOffset.y + self.viewWH/2.0;
    }
    else viewCenterSpace = self.collectionView.contentOffset.x + self.viewWH/2.0;
    
    NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
    NSInteger index = viewCenterSpace / self.itemWH;
    NSInteger count = (visibleCount - 1) / 2;
    NSInteger minIndex = MAX(0, (index - count));
    NSInteger maxIndex = MIN(cellCount, (index + count + 1));
    
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:maxIndex - minIndex];
    for (NSInteger i = minIndex; i < maxIndex; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        [array addObject:layoutAttributes];
    }
    return array;
}

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    CGFloat viewCenterIndex = 0.0;
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        viewCenterIndex = roundf((proposedContentOffset.y + self.viewWH / 2.0 - self.itemWH / 2.0) / self.itemWH);
        proposedContentOffset.y = self.itemWH * viewCenterIndex + self.itemWH / 2.0 - self.viewWH / 2.0;
    }
    else {
        viewCenterIndex = roundf((proposedContentOffset.x + self.viewWH / 2.0 - self.itemWH / 2.0) / self.itemWH);
        proposedContentOffset.x = self.itemWH * viewCenterIndex + self.itemWH / 2.0 - self.viewWH / 2.0;
    }
    return proposedContentOffset;
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return !CGRectEqualToRect(newBounds, self.collectionView.bounds);
}
@end
